home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Mania 5
/
MacMania 5.toast
/
/
Internet software
/
NewsWatcher
/
NW Source
/
Source
/
wind.c
< prev
next >
Wrap
Text File
|
1997-01-09
|
21KB
|
819 lines
/*----------------------------------------------------------------------------
wind.c
This module handles the commands in the Windows menu. It also contains
a few general purpose window management functions.
Copyright © 1994-1997, Northwestern University.
----------------------------------------------------------------------------*/
#include <Icons.h>
#include <stdio.h>
#include "glob.h"
#include "full.h"
#include "menus.h"
#include "newswatcher.h"
#include "wind.h"
#include "dialog.h"
#include "drawutil.h"
#include "windutil.h"
#include "memutil.h"
#include "strutil.h"
#include "header.h"
#include "iconutil.h"
#include "resutil.h"
#include "fileutil.h"
#include "help.h"
#define kOpenPadlockID 210
#define kClosedPadlockID 211
/*----------------------------------------------------------------------------
DoCycleWindows
Handle the "Cycle Windows" command.
Entry: wind = pointer to window.
----------------------------------------------------------------------------*/
void DoCycleWindows (WindowPtr wind)
{
SendBehind(wind, nil);
}
/*----------------------------------------------------------------------------
DoZoomWindow
Handle the "Zoom Window" command.
Entry: wind = pointer to window.
Exit: function result = error code.
----------------------------------------------------------------------------*/
OSErr DoZoomWindow (WindowPtr wind)
{
WStateData **wState;
Rect r;
OSErr err = noErr;
wState = (WStateData**)((WindowPeek)wind)->dataHandle;
r = (**wState).stdState;
if (WindRectEqualRect(wind, &r)) {
err = DoZoom(wind, inZoomIn);
} else {
err = DoZoom(wind, inZoomOut);
}
return err;
}
/*----------------------------------------------------------------------------
DoShowHideFullGroupList
Handle the "Show/Hide Full Group List" command.
Exit: function result = error code.
----------------------------------------------------------------------------*/
OSErr DoShowHideFullGroupList (void)
{
OSErr err = noErr;
if (((WindowPeek)gFullGroupWindow)->visible) {
HideWindow(gFullGroupWindow);
SetWindowsMenuShowHideFullGroupList(true);
} else {
if (gMustDoZoomOnShowFullGroupList) {
err = DoZoom(gFullGroupWindow, inZoomOut);
if (err != noErr) return err;
}
gMustDoZoomOnShowFullGroupList = false;
MyShowWindow(gFullGroupWindow);
SetWindowsMenuShowHideFullGroupList(false);
MySelectWindow(gFullGroupWindow);
}
return noErr;
}
/*----------------------------------------------------------------------------
RebuildWindowsMenu
Rebuild the list of open windows in the Windows menu.
----------------------------------------------------------------------------*/
void RebuildWindowsMenu (void)
{
WindowPtr wind;
MenuHandle menu;
Str255 title;
Str255 menuStr;
short item, len, numItems, numDel;
TWindowKind kind;
TWindow **info;
Handle fullText;
CStr255 from;
menu = GetMenuHandle(kWindMenu);
numItems = CountMItems(menu);
numDel = numItems - kFirstOpenWindItem + 1;
while (numDel--) DeleteMenuItem(menu, kFirstOpenWindItem);
item = kFirstOpenWindItem;
for (wind = FrontWindow();
wind != nil;
wind = (WindowPtr)((WindowPeek)wind)->nextWindow)
{
kind = GetMyWindowKind(wind);
if (kind != kNotOurWind && ((WindowPeek)wind)->visible) {
GetWTitle(wind, title);
len = *title;
if (len > 0 && title[1] == checkMark) {
len--;
BlockMoveData(title+2, title+1, len);
*title = len;
}
if (kind == kArticle) {
info = (TWindow**)GetWRefCon(wind);
fullText = (**info).fullText;
if (FindHeaderCString(fullText, "From", from, sizeof(from))) {
FormatAuthorName(from);
p2cstr(title);
sprintf((char*)menuStr, "%.25s, %.200s", from, (char*)title);
c2pstr((char*)menuStr);
} else {
CopyPascalString(menuStr, title);
}
} else {
CopyPascalString(menuStr, title);
}
len = *menuStr;
if (len > 200) {
len = 200;
*menuStr = len;
}
if (len > 0) {
if (menuStr[1] == '-') {
if (len < 255) len++;
BlockMoveData(menuStr+1, menuStr+2, len-1);
menuStr[1] = ' ';
*menuStr = len;
}
} else {
*menuStr = 1;
menuStr[1] = 'x';
}
AppendMenu(menu, "\px");
SetMenuItemText(menu, item, menuStr);
if (wind == FrontWindow()) CheckItem(menu, item, true);
item++;
}
}
}
/*----------------------------------------------------------------------------
SelectWindMenu
Handle a window selection command in the Windows menu.
Entry: item = item number of menu command.
----------------------------------------------------------------------------*/
void SelectWindMenu (short item)
{
WindowPtr wind;
item -= kFirstOpenWindItem;
for (wind = FrontWindow();
wind != nil;
wind = (WindowPtr)((WindowPeek)wind)->nextWindow)
{
if (GetMyWindowKind(wind) != kNotOurWind && ((WindowPeek)wind)->visible) {
if (item <= 0) {
MySelectWindow(wind);
return;
} else {
item--;
}
}
}
}
/*----------------------------------------------------------------------------
GetMyWindowKind
Get the window kind.
Entry: wind = pointer to window.
Exit: function result = window kind.
----------------------------------------------------------------------------*/
TWindowKind GetMyWindowKind (WindowPtr wind)
{
TWindow **info;
short windowKind;
if (wind == nil) return kNotOurWind;
windowKind = ((WindowPeek)wind)->windowKind;
if (windowKind < 0) return kNotOurWind;
if (windowKind == dialogKind && wind != gMyCurDialog) return kNotOurWind;
info = (TWindow**)GetWRefCon(wind);
if (info == nil) return kNotOurWind;
return (**info).kind;
}
/*----------------------------------------------------------------------------
CreateNewWindow
Create a new window.
Entry: kind = window kind.
title = window title.
font = window font.
size = window font size.
Exit: function result = error code.
*theWindow = pointer to new window.
----------------------------------------------------------------------------*/
OSErr CreateNewWindow (TWindowKind kind, StringPtr title,
StringPtr font, short size, WindowPtr *theWindow)
{
WindowPtr wind = nil, prev, next, behind;
TWindow **info;
Rect bounds;
OSErr err = noErr;
short fontNum, wDefProcID;
GrafPtr port;
FontInfo fontInfo;
GetPort(&port);
SetRect(&bounds, 0, 0, 100, 100);
/* Compute the window layer position. If the frontmost window belonging
to NewsWatcher is the status window, create the new window behind
the status window. Otherwise, create the new window in front of the
frontmost window belonging to NewsWatcher. */
prev = nil;
next = FrontWindow();
while (next != nil && ((WindowPeek)next)->windowKind < 0) {
prev = next;
next = (WindowPtr)((WindowPeek)next)->nextWindow;
}
if (GetMyWindowKind(next) == kStatus) {
behind = next;
} else if (prev == nil) {
behind = (WindowPtr)-1;
} else {
behind = prev;
}
wDefProcID = kind == kStatus ? movableDBoxProc : zoomDocProc;
err = MyNewWindow(&bounds, title, false, wDefProcID, behind, true, 0, &wind);
if (err != noErr) goto exit;
SetPort(wind);
GetFontNumber(font, &fontNum);
TextFont(fontNum);
TextSize(size);
err = MyNewHandle(sizeof(TWindow), &info);
if (err != noErr) goto exit;
(**info).kind = kind;
SetWRefCon(wind, (long)info);
GetFontInfo(&fontInfo);
(**info).fontInfo = fontInfo;
(**info).lineHeight = fontInfo.leading + fontInfo.ascent + fontInfo.descent;
*theWindow = wind;
SetPort(port);
return noErr;
exit:
MyDisposeWindow(wind);
SetPort(port);
return err;
}
/*----------------------------------------------------------------------------
PositionNewWindow
Position a new window.
Entry: wind = pointer to window.
width = window width.
height = window height.
----------------------------------------------------------------------------*/
void PositionNewWindow (WindowPtr wind, short width, short height)
{
WindowPtr theWind;
WindowPeek theWindPeek;
TWindowKind kind;
for (theWind = FrontWindow();
theWind != nil;
theWind = (WindowPtr)((WindowPeek)theWind)->nextWindow)
{
theWindPeek = (WindowPeek)theWind;
if (theWindPeek->windowKind < 0) continue;
if (theWind == wind) continue;
if (!theWindPeek->visible) continue;
kind = GetMyWindowKind(theWind);
if (kind == kStatus || kind == kNotOurWind || kind == kDummy) continue;
if (gStartingUp && theWind == gFullGroupWindow) continue;
break;
}
StaggerWindow(wind, width, height, theWind, gPrefs.dontCoverFinderIcons);
}
/*----------------------------------------------------------------------------
MyShowWindow
Show a window.
Entry: wind = pointer to window.
----------------------------------------------------------------------------*/
void MyShowWindow (WindowPtr wind)
{
EventRecord ev;
if (gInBackground) HandleActivate(wind, false);
ShowWindow(wind);
while (WaitNextEvent(activMask | osMask, &ev, 0, nil))
HandleEvent(&ev);
}
/*----------------------------------------------------------------------------
SaveWindPos
Save a window position.
Entry: wind = pointer to window.
Exit: *pos = saved position.
----------------------------------------------------------------------------*/
void SaveWindPos (WindowPtr wind, TSavedWindPos *pos)
{
TWindow **info;
GrafPtr port;
WStateData **wState;
Rect r, stdState;
info = (TWindow**)GetWRefCon(wind);
if ((**info).windPosValid) {
GetPort(&port);
SetPort(wind);
pos->valid = true;
pos->oldFormat = false;
r = wind->portRect;
LocalToGlobalRect(&r);
wState = (WStateData**)((WindowPeek)wind)->dataHandle;
stdState = (**wState).stdState;
pos->zoomed = EqualRect(&stdState, &r);
if (pos->zoomed) {
pos->userState = (**wState).userState;
} else {
pos->userState = r;
}
SetPort(port);
} else {
pos->valid = false;
}
}
/*----------------------------------------------------------------------------
RestoreWindPos
Restore a window position.
Entry: wind = pointer to window.
pos = pointer to saved position.
Exit: *needsZooming = true if window should be zoomed.
----------------------------------------------------------------------------*/
void RestoreWindPos (WindowPtr wind, TSavedWindPos *pos, Boolean *needsZooming)
{
TWindow **info;
GrafPtr port;
WStateData **wState;
Rect r;
Boolean mainScreen, onOneScreen, useDefaultPos;
short width, height;
GetPort(&port);
SetPort(wind);
info = (TWindow**)GetWRefCon(wind);
useDefaultPos = !pos->valid;
if (!useDefaultPos) {
MoveWindow(wind, pos->userState.left, pos->userState.top, false);
if (pos->oldFormat) {
*needsZooming = true;
} else {
width = pos->userState.right - pos->userState.left;
height = pos->userState.bottom - pos->userState.top;
SizeWindow(wind, width, height, false);
*needsZooming = pos->zoomed;
}
if (!WindOnScreen(wind)) useDefaultPos = true;
}
(**info).windPosValid = !useDefaultPos;
if (useDefaultPos) {
if ((**info).kind == kGroup && (**info).groupKind == kFullGroup) {
MoveWindow(wind, 10, GetMBarHeight() + 30, false);
GetDominantScreen(gFullGroupWindow, &r, &mainScreen, &onOneScreen);
MoveWindow(wind, r.right - wind->portRect.right - 64,
r.top + GetMBarHeight() + 30, false);
} else {
PositionNewWindow(wind, wind->portRect.right, wind->portRect.bottom);
}
*needsZooming = true;
}
wState = (WStateData**)((WindowPeek)wind)->dataHandle;
r = wind->portRect;
LocalToGlobalRect(&r);
(**wState).userState = r;
SetPort(port);
}
/*----------------------------------------------------------------------------
SaveWindPosAsResource
Save a window position as a 'WPOS' id=128 resource on the current
resource file.
Entry: wind = pointer to window.
Exit: function result = error code.
----------------------------------------------------------------------------*/
OSErr SaveWindPosAsResource (WindowPtr wind)
{
TSavedWindPos pos;
Handle h = nil;
OSErr err = noErr;
TWindow **info;
SaveWindPos(wind, &pos);
err = MyPtrToHand(&pos, &h, sizeof(pos));
if (err != noErr) goto exit;
err = MyReplaceResource(h, 'WPOS', 128, "\p");
if (err != noErr) goto exit;
info = (TWindow**)GetWRefCon(wind);
(**info).movedSinceLastSave = false;
return noErr;
exit:
MyDisposeHandle(h);
return err;
}
/*----------------------------------------------------------------------------
SaveWindPosToFile
If necessary, save just a changed window position to a document file,
without changing the window's last mod date.
Entry: wind = pointer to window.
Exit: function result = error code.
----------------------------------------------------------------------------*/
OSErr SaveWindPosToFile (WindowPtr wind)
{
TWindow **info;
AliasHandle alias;
FSSpec fSpec;
OSErr err = noErr;
Boolean wasChanged;
short refNum = 0;
unsigned long lastModDateTime;
FInfo fInfo;
/* Note that errors are ignored. This is not a critical operation,
and we don't want to interfere with closing a window just because
something fails here. */
info = (TWindow**)GetWRefCon(wind);
alias = (**info).alias;
if (alias == nil || !(**info).movedSinceLastSave) return noErr;
err = ResolveAlias(nil, alias, &fSpec, &wasChanged);
if (err != noErr) return noErr;
err = FSpGetFInfo(&fSpec, &fInfo);
if (err != noErr) return noErr;
if (fInfo.fdCreator != kNewsWatcherSignature) return noErr;
err = GetLastModDateTime(&fSpec, &lastModDateTime);
if (err != noErr) return noErr;
err = MyFSpOpenResFile(&fSpec, fsRdWrPerm, &refNum);
if (err != noErr) return noErr;
err = SaveWindPosAsResource(wind);
if (err != noErr) goto exit;
MyCloseResFile(refNum);
err = SetLastModDateTime(&fSpec, lastModDateTime);
return noErr;
exit:
if (refNum != 0) MyCloseResFile(refNum);
return noErr;
}
/*----------------------------------------------------------------------------
RestoreLockedWindowPosition
Restore a locked window position.
Entry: wind = pointer to subject, article, or message window.
width = unlocked width of window.
height = unlocked height of window.
windPosLocked = true if this kind of window has a saved
locked position.
*windLocn = saved locked window position.
If this kind of window has a saved locked window position, and if
no other window of this kind is already open, the saved locked window
position is restored. Otherwise, the default window postion is set.
----------------------------------------------------------------------------*/
void RestoreLockedWindowPosition (WindowPtr wind, short width, short height,
Boolean windPosLocked, Rect *windLocn)
{
TWindow **info;
TWindowKind kind;
WindowPtr w;
GrafPtr port;
WStateData **wState;
Rect r;
GetPort(&port);
SetPort(wind);
info = (TWindow**)GetWRefCon(wind);
kind = (**info).kind;
if (windPosLocked) {
for (w = FrontWindow(); w != nil; w = (WindowPtr)((WindowPeek)w)->nextWindow) {
if (kind == GetMyWindowKind(w) && w != wind) {
windPosLocked = false;
break;
}
}
}
if (windPosLocked) {
MoveWindow(wind, windLocn->left, windLocn->top, false);
SizeWindow(wind, windLocn->right - windLocn->left,
windLocn->bottom - windLocn->top, false);
if (WindOnScreen(wind)) {
wState = (WStateData**)((WindowPeek)wind)->dataHandle;
r = wind->portRect;
LocalToGlobalRect(&r);
(**wState).userState = r;
} else {
windPosLocked = false;
}
}
if (!windPosLocked) {
PositionNewWindow(wind, width, height);
}
(**info).windPosLocked = windPosLocked;
SetPort(port);
}
/*----------------------------------------------------------------------------
DrawPadlockIcon
Draw the padlock icon in a window.
Entry: wind = pointer to subject, article, or message window.
----------------------------------------------------------------------------*/
void DrawPadlockIcon (WindowPtr wind)
{
TWindow **info;
short windHeight;
Rect padlockRect;
info = (TWindow**)GetWRefCon(wind);
windHeight = wind->portRect.bottom;
SetRect(&padlockRect, 1, windHeight-17, 17, windHeight-1);
PlotIconID(&padlockRect, 0, ttNone,
(**info).windPosLocked ? kClosedPadlockID : kOpenPadlockID);
}
/*----------------------------------------------------------------------------
HandlePadlockClick
Check for and handle a click on a padlock icon.
Entry: wind = pointer to subject, article, or message window.
where = location of mouse down event, in local coords.
windPosLocked = pointer to windPosLocked preference for
this kind of window.
windLocn = pointer to saved locked window position for
this kind of window.
Exit: function result = true if padlock clicked.
----------------------------------------------------------------------------*/
Boolean HandlePadlockClick (WindowPtr wind, Point where,
Boolean *windPosLocked, Rect *windLocn)
{
TWindow **info;
short windHeight, iconID;
Rect padlockRect, hotRect;
GrafPtr port;
WindowPtr w;
TWindowKind kind;
GetPort(&port);
SetPort(wind);
info = (TWindow**)GetWRefCon(wind);
windHeight = wind->portRect.bottom;
SetRect(&padlockRect, 0, windHeight-16, 16, windHeight);
hotRect = padlockRect;
hotRect.top += 2;
hotRect.right -= 1;
iconID = (**info).windPosLocked ? kClosedPadlockID : kOpenPadlockID;
if (!TrackIconClick(where, &padlockRect, &hotRect, iconID)) {
SetPort(port);
return false;
}
SetRect(&padlockRect, 0, windHeight - 13, 13, windHeight);
(**info).windPosLocked = *windPosLocked = !(**info).windPosLocked;
InvalRect(&padlockRect);
if (*windPosLocked) {
*windLocn = wind->portRect;
LocalToGlobalRect(windLocn);
SetPort(port);
kind = (**info).kind;
for (w = FrontWindow(); w != nil; w = (WindowPtr)((WindowPeek)w)->nextWindow) {
if (kind == GetMyWindowKind(w) && w != wind) {
info = (TWindow**)GetWRefCon(w);
if ((**info).windPosLocked) {
(**info).windPosLocked = false;
SetPort(w);
windHeight = w->portRect.bottom;
SetRect(&padlockRect, 0, windHeight - 13, 13, windHeight);
InvalRect(&padlockRect);
}
}
}
}
KillBalloon();
SetPort(port);
return true;
}
/*----------------------------------------------------------------------------
RecordNewLockedWindowPosition
Record the new locked window position after a locked window is resized.
Entry: wind = pointer to subject, article, or message window.
windLocn = pointer to saved locked window position for
this kind of window.
Exit: *windLocn = new locked window position.
----------------------------------------------------------------------------*/
void RecordNewLockedWindowPosition (WindowPtr wind, Rect *windLocn)
{
TWindow **info;
GrafPtr port;
info = (TWindow**)GetWRefCon(wind);
if (!(**info).windPosLocked) return;
*windLocn = wind->portRect;
GetPort(&port);
SetPort(wind);
LocalToGlobalRect(windLocn);
SetPort(port);
}
/*----------------------------------------------------------------------------
MySelectWindow
Move a window to the front, or just behind the Status window if the
Status window is open.
Entry: wind = pointer to window.
----------------------------------------------------------------------------*/
void MySelectWindow (WindowPtr wind)
{
WindowPtr front;
WindowRef wRef;
front = MyFrontWindow();
if (GetMyWindowKind(front) == kStatus) {
wRef = (WindowRef)wind;
PaintOne(wRef, ((WindowPeek)wRef)->strucRgn);
CalcVis(wRef);
SendBehind(wind, front);
} else {
SelectWindow(wind);
}
}
/*----------------------------------------------------------------------------
AdjustWindowTitlesOnResume
Adjust the titles of all open windows which correspond to saved files
on a resume event, in case the user changed the file names.
----------------------------------------------------------------------------*/
void AdjustWindowTitlesOnResume (void)
{
WindowPtr wind;
TWindowKind kind;
TWindow **info;
FSSpec fSpec;
Boolean wasChanged;
OSErr err = noErr;
Str255 title;
for (wind = FrontWindow();
wind != nil;
wind = (WindowPtr)((WindowPeek)wind)->nextWindow)
{
kind = GetMyWindowKind(wind);
if (kind != kGroup && kind != kMessage) continue;
info = (TWindow**)GetWRefCon(wind);
if ((**info).alias == nil) continue;
err = ResolveAlias(nil, (**info).alias, &fSpec, &wasChanged);
if (err == noErr) {
GetWTitle(wind, title);
if (EqualString(title, fSpec.name, false, true)) continue;
SetWTitle(wind, fSpec.name);
} else {
MyDisposeHandle((**info).alias);
(**info).alias = nil;
(**info).changed = true;
}
}
}